home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_12_01 / yuen / cschlr.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1993-11-10  |  4.9 KB  |  246 lines

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include "cschlr.hpp"
  4.  
  5. const int MAIN = CSC_NO_THREAD;        //main prgram context
  6. const int DUMMY = MAIN + 1;        //temporary context
  7. const int EMPTY =-1;            //no delayed thread marker
  8.  
  9. /* The following static varaible is used to facilitate the
  10.    implementation of Kill. This limits the number of Cschlr
  11.    object per Windows application to 1 only */
  12. static Cschlr *schlr;
  13.  
  14. /* Used for the implicit termination of a thread when
  15.    execution falls through the thread function body */
  16. static void Kill()
  17. {
  18.   schlr->Suicide();
  19. }
  20.  
  21.  
  22. /* Used to check if it is time to wake up the sleeping
  23.    threads. */
  24. void Cschlr::WakeUp()
  25. {
  26.   time_t current;
  27.   schlr_table *ptr;
  28.   
  29.   /* check time and dispatch thread */
  30.   time(¤t);
  31.   while ((head != EMPTY) &&
  32.          (current >= (ptr = (table + head))->wakeuptime))
  33.     {
  34.     readyQ.Enqueue(head);
  35.     head = ptr->next;
  36.     ptr->next = EMPTY;
  37.     }
  38. }
  39.  
  40.  
  41. /* Used to perform a task switch. Control is passed 
  42.    back to the Windows PeekMessage loop */
  43. void Cschlr::Switch(Csemq *sem)
  44. {
  45.   WakeUp();
  46.   sem->Enqueue(nRunning);
  47.   task[nRunning]->Transfer(*task[MAIN]);
  48. }
  49.  
  50.  
  51. /* Constructor to set up the task table */
  52. Cschlr::Cschlr()
  53. {
  54.   nTask = 0;
  55.   nRunning = CSC_NO_THREAD;
  56.   head = EMPTY;
  57.   table = new schlr_table[CSC_NO_THREAD];
  58.   schlr = this;
  59.  
  60.   //used to resume main program
  61.   task[MAIN] = new Cthread(NULL, 0, NULL, 0);
  62.  
  63.   //used in Suicide to switch task
  64.   task[DUMMY] = new Cthread(NULL, 0, NULL, 0);  
  65. }
  66.  
  67.  
  68. /* Empty destructor */
  69. Cschlr::~Cschlr()
  70. {
  71.   //do nothing
  72. }
  73.  
  74.  
  75. /* Used to create a thread and pass to it a user variable */
  76. int Cschlr::CreateThread(THDFN func, int stacksize, void *param)
  77. {
  78.   THDFN retaddr;    //these two variables must appear
  79.   void *ptr;        //together for CreateThread to work
  80.   int i;
  81.  
  82.   int thread = CSC_NO_THREAD;
  83.  
  84.   if (nTask < CSC_NO_THREAD + 1)
  85.     {
  86.     for (i = 0; i < CSC_NO_THREAD + 1; i++)
  87.       {
  88.       if (task[i] == NULL)
  89.         break;
  90.       }
  91.     retaddr = Kill;    //set return address to point to Kill
  92.     ptr = param;    //set user parameter pointer
  93.     task[i] = new Cthread(func, stacksize, (int *) &retaddr, 4);
  94.     readyQ.Enqueue(i);
  95.     thread = nTask++;
  96.     }
  97.     
  98.   return (thread);
  99. }
  100.  
  101.  
  102. /* Used by a calling thread to commit suicide or
  103.    self-terminate */
  104. void Cschlr::Suicide()
  105. {
  106.     int current;
  107.     
  108.     current = nRunning;
  109.     nRunning = readyQ.Dequeue();
  110.     delete task[current];
  111.     task[current] = NULL;
  112.     nTask--;
  113.     task[DUMMY]->Transfer(*task[nRunning]);
  114. }
  115.  
  116.  
  117. /* Used to create a semaphore object */
  118. Csemq* Cschlr::CreateSem(long lValue)
  119. {
  120.   return (new Csemq(lValue));
  121. }
  122.  
  123.  
  124. /* Used to destroy a semaphore object */
  125. void Cschlr::DestroySem(Csemq* sem)
  126. {
  127.   delete sem;
  128. }
  129.  
  130.  
  131. /* Used to signal a semaphore */
  132. void Cschlr::Signal(Csemq *sem, long lMaxCount)
  133. {
  134.   if (sem->GetType() == CST_COUNT)
  135.     {
  136.     if (sem->GetCount() < lMaxCount)
  137.       sem->UpdateCount(1);
  138.     }
  139.   else
  140.     {
  141.     readyQ.Enqueue(sem->Dequeue());
  142.     }
  143. }
  144.  
  145.  
  146. /* Used to wait on a semaphore */
  147. void Cschlr::Wait(Csemq *sem)
  148. {
  149.   
  150.   if (sem->GetType() == CST_COUNT)
  151.     {
  152.     if (!sem->GetCount())
  153.       {
  154.       //move running thread to semaphore queue and 
  155.       //switch to a ready-to-run thread
  156.       Switch(sem);
  157.       }
  158.     else
  159.       //decrement sempahore count and continue execution
  160.       sem->UpdateCount(-1);
  161.     }
  162.   else
  163.     {
  164.     //move running thread to semaphore queue and 
  165.     //switch to a ready-to-run thread
  166.     Switch(sem);
  167.     }
  168. }
  169.  
  170.  
  171. /* Used to give up the cpu voluntarily */
  172. void Cschlr::Preempt()
  173. {
  174.   Switch(&readyQ);
  175. }
  176.  
  177.  
  178. /* Used to put the calling thread to sleep for the
  179.    specified number of seconds */
  180. void Cschlr::Sleep(long lSeconds)
  181. {
  182.   time_t current;
  183.   schlr_table *ptr;
  184.   schlr_table *thread;
  185.   int prev;
  186.   int next;
  187.  
  188.   current = time(0) + lSeconds;    //init wakeup time
  189.   
  190.   if (head == EMPTY)    
  191.     {                //no thread delayed
  192.     head = nRunning;
  193.     next = EMPTY;
  194.     }
  195.   else                //scan delayed threads
  196.     {  
  197.     prev = EMPTY;
  198.     next = head;
  199.     while ((next != EMPTY) && (current >= 
  200.     (ptr = (table + next))->wakeuptime))
  201.       {
  202.       prev = next;
  203.       next = ptr->next;
  204.       }
  205.       
  206.     if (prev == EMPTY)
  207.       head = nRunning;
  208.     else
  209.       (table + prev)->next = nRunning;
  210.     }
  211.   
  212.   ptr = (table + nRunning);
  213.   ptr->wakeuptime = current;
  214.   ptr->next = next;
  215.   
  216.   Switch(&waitQ);
  217.   
  218. }
  219.  
  220.  
  221. /* Used to retrieve the status of a semaphore */
  222. void Cschlr::GetSemStates(Csemq *sem, long &lCount, int &fWait)
  223. {
  224.   if (sem->GetType() == CST_COUNT)
  225.     {
  226.     lCount = sem->GetCount();
  227.     fWait = 0;
  228.     }
  229.   else
  230.     {
  231.     lCount = 0;
  232.     fWait = 1;
  233.     }
  234. }
  235.  
  236.  
  237. /* Used by the main PeekMessage loop to multiplex the
  238.    cpu among a number of threads */
  239. void Cschlr::Run()
  240. {
  241.   if ((nRunning = readyQ.Dequeue()) != CSC_NO_THREAD)
  242.     task[MAIN]->Transfer(*task[nRunning]);
  243.   else
  244.     WakeUp();
  245. }
  246.